#ifndef MISC_FUNCTIONS_H_INCLUDED
#define MISC_FUNCTIONS_H_INCLUDED

#include <direct.h> // for getcwd
#include <stdlib.h>// for MAX_PATH
#include "c_tag.h"
#include "xmlParser.h"

/**tokenize((const string& str, vector<string>& tokens, const string& delimiters)
Splits the string passed to it at every delimiter
and then puts each substr into the tokens vector**/
void tokenize(const string& str, vector<string>& tokens, const string& delimiters)
{
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}

void error_report(string message)
{
    ofstream err_file("error_log.txt", ofstream::out|ofstream::app);  //Open the error.txt file, in append mode (add to the end of the file)

    if( err_file.is_open() )  //If the file was opened properly TODO: HANDLE IT IF IT DOESN'T!!!
    {
        err_file << message << endl;  //Output the error message and a newline to the file.
        err_file.close();  //Close the file.
    }
}

//Converts a string to all lower-case
string toLower(string input)
{
    string output;  //A string to hold the output
    for(unsigned int i=0; i<input.length(); i++)  //Loop through each character in the original string
    {
        output+=tolower( input.at(i) );  //Convert it to lowercase and add it to the output string
    }
    return output;  //Return "output".
}

//Converts a string to all upper-case
string toUpper(string input)
{
    string output;  //A string to hold the output
    for(unsigned int i=0; i<input.length(); i++)  //Loop through the characters in the original string
    {
        output+=toupper( input.at(i) );  //Convert each one to uppercase and add it to the output string
    }
    return output;  //Return "output".
}

//Gets indentation string
string getIndent(vector<c_tag> vec)
{
    string ret = "";  //Create a blank string to use later as a return value
    for(unsigned int i=0; i<vec.size(); i++)  //Repeat for the number of elements in the vector
    {
        ret+="\t";  //Add one tab (horizantal indent) to the return value (ret)
    }
    return ret;  //Return "ret"
}

//Takes a string filename, and removes the extension.
///TODO: REPLACE THE LOOP WITH find_last_of???
std::string stripExtension(string fileName)
{
  const int length = fileName.length();  //An integer to hold the length of the filename
  for (int i=0; i!=length; ++i)  //Repeat for each character in the file name
  {
    if (fileName[i]=='.')  //If it's a '.'
    {
      return fileName.substr(0,i);  //Return the filename up to that point.
    }
  }
  return fileName;  //Return the original filename if no decimal/'.' was found.
}

//Returns the path the .exe file is being run from
std::string getPath()
{
    char buffer[_MAX_PATH];
    getcwd(buffer, _MAX_PATH);

    string path = buffer + string("\\");

    return path;
}

//Check if a node has "grandchildren"
bool hasGrandchildren(XMLNode thisNode)
{
    for(int i=0; i<thisNode.nChildNode(); i++)  //Loop through each of this node's children
    {
        if(thisNode.getChildNode(i).nChildNode()>0)  //If this child had children (the orignal tag's grandchildren)...
        {
            return true;  //Return true (it does have grandchildren
        }
    }
    return false;  //Return false, this only happens if none of the tag's children had children
}

//Outputs a nome to an XML file
void outputNode(ofstream& outputFile, std::vector<c_tag> tag_list, XMLNode thisNode, int indent, bool uppercase)
{
    int index = -1;  //A variable to hold the index of the matching tag
    for(unsigned int i=0; i<tag_list.size(); i++)  //Loop through all the tags in the list
    {
        if( toLower(tag_list.at(i).get_xml_name()) == toLower(thisNode.getName()) )  //If the name of the tag at 'i' and the name of the current node match (not case-sensitive)
        {
            index = i;  //Set index to 'i'
            break;  //And break out of the loop
        }
    }

    if(index!=-1)  //If it found a match then index will have been changed to that tag's location in the vector.
    {
        for(int i=0; i<indent; i++) {outputFile << "\t";}  //Add indentation
        string tagName = tag_list.at(index).get_raw_name();  //Get the "raw" name of the tag as a stirng
        if(uppercase) { tagName = toUpper(tagName); }  //If the uppercase box is checked, convert the name to all-uppercase
        outputFile << "[" << tagName;  //Output the strating bracket '[' and the tag name

        if(thisNode.nText())  //If the node has text in it (I.E. only has the single argument
        {
            outputFile << ":";  //Output a colon
            outputFile << thisNode.getText();  //Then the text in the node
            outputFile << "]" << endl;  //And then the closing bracket ']'
        }
        else if( thisNode.nChildNode()==0 )  //If the tag has no children (and doesn't have text, since this is an 'else if')
        {
            outputFile << "]" << endl;  //Just output the closing bracket
        }
        else if( hasGrandchildren(thisNode) )  //If the tag has grandchildren
        {
            if( tag_list.at(index).get_attribute_count()>0 )  //If the tag_list has more than one attribute listed for this tag
            {
                for(int i=0; i<tag_list.at(index).get_attribute_count(); i++)  //Loop through for the number of attributes listed
                {
                    string attr_name = tag_list.at(index).get_attribute(i);  //Get the name of the attribute
                    if( thisNode.nChildNode(attr_name.c_str())>0 )  //If the tag has a child with the same name as the attribute
                    {
                        outputFile << ":" << thisNode.getChildNode(attr_name.c_str()).getText();  //Add a colon and the attribute to the tag
                    }
                }
            }

            outputFile << "]" << endl;  //Add the closing bracket

            for(int i=0; i<thisNode.nChildNode(); i++)  //Loop through the tag's children
            {
                outputNode(outputFile, tag_list, thisNode.getChildNode(i), indent+1, uppercase);  //And output each one
            }
        }
        else  //Else, if the tag doesn't fit any of the above requirements
        {
            for(int i=0; i<thisNode.nChildNode(); i++)  //Loop through it's children
            {
                outputFile << ":" << thisNode.getChildNode(i).getText();  //And add each of them as an argument
            }
            outputFile << "]" << endl;  //Add the closing bracket.
        }
    }
}

#endif // MISC_FUNCTIONS_H_INCLUDED
